package game.service.impl;

import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import common.config.exception.CustomException;
import common.config.exception.ShouldNeverHappenException;
import common.model.enums.ClassificationTypeEnum;
import common.model.po.GClassification;
import common.model.po.GProduct;
import common.model.po.GProductRequirement;
import common.model.po.GProductUnlock;
import common.model.response.base.Result;
import common.util.TreeUtil;
import game.mapper.GProductMapper;
import game.model.converter.GProductConverter;
import game.model.request.SaveProductRequest;
import game.model.vo.ClassificationTreeVo;
import game.model.vo.ProductGroupVo;
import game.service.GClassificationService;
import game.service.GProductRequirementService;
import game.service.GProductService;
import game.service.GProductUnlockService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 服务实现类
 *
 * @author 米泽鹏
 * @since 2024-01-24 下午 07:10
 */
@Service
public class GProductServiceImpl extends ServiceImpl<GProductMapper, GProduct> implements GProductService {

	@Resource
	private GProductMapper mapper;
	@Resource
	private GClassificationService classificationService;
	@Resource
	private GProductRequirementService requirementService;
	@Resource
	private GProductUnlockService unlockService;

	@Override
	public List<ProductGroupVo> getAllProductGroup() {
		List<ProductGroupVo> productGroupVoList = Lists.newArrayList();
		// 查询所有商品
		List<GProduct> productList = list();
		// 将商品按照类别分组
		LinkedHashMap<Long, List<GProduct>> map = productList.stream().collect(Collectors.groupingBy(GProduct::getClassificationId, LinkedHashMap::new, Collectors.toList()));
		// 查询商品分类树
		List<ClassificationTreeVo> classificationTree = classificationService.getClassificationTree(ClassificationTypeEnum.PRODUCT);
		// 类别缓存
		Map<Long, GClassification> classificationMap = Maps.newHashMap();
		// 类别排序
		LinkedHashMap<Long, List<GProduct>> sortedMap = map.entrySet().stream().sorted((entry1, entry2) -> {
			// 待比较的两个类别id
			Long classificationId1 = entry1.getValue().get(0).getClassificationId();
			Long classificationId2 = entry2.getValue().get(0).getClassificationId();
			// 找出从根节点到该类别的路径
			List<Long> path1 = TreeUtil.findPathToNode(classificationTree, classificationTreeVo -> classificationId1.equals(classificationTreeVo.getId()), ClassificationTreeVo::getId, ClassificationTreeVo::getChildren);
			if (CollUtil.isEmpty(path1)) {
				throw new CustomException("商品分类不存在");
			}
			List<Long> path2 = TreeUtil.findPathToNode(classificationTree, classificationTreeVo -> classificationId2.equals(classificationTreeVo.getId()), ClassificationTreeVo::getId, ClassificationTreeVo::getChildren);
			if (CollUtil.isEmpty(path2)) {
				throw new CustomException("商品分类不存在");
			}
			int minSize = Math.min(path1.size(), path2.size());
			for (int i = 0; i < minSize; i++) {
				Long id1 = path1.get(i);
				Long id2 = path2.get(i);
				// 跳过公共父节点
				if (id1.equals(id2)) {
					continue;
				}
				Optional<ClassificationTreeVo> optional1 = TreeUtil.findInTree(classificationTree, classificationTreeVo -> id1.equals(classificationTreeVo.getId()), ClassificationTreeVo::getChildren);
				if (!optional1.isPresent()) {
					throw new CustomException("商品分类不存在");
				}
				Optional<ClassificationTreeVo> optional2 = TreeUtil.findInTree(classificationTree, classificationTreeVo -> id2.equals(classificationTreeVo.getId()), ClassificationTreeVo::getChildren);
				if (!optional2.isPresent()) {
					throw new CustomException("商品分类不存在");
				}
				return optional1.get().getSort().compareTo(optional2.get().getSort());
			}
			throw new ShouldNeverHappenException();
		}).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (products1, products2) -> {
			List<GProduct> products = new ArrayList<>();
			products.addAll(products1);
			products.addAll(products2);
			return products;
		}, LinkedHashMap::new));
		// 获取商品的全类别
		for (Map.Entry<Long, List<GProduct>> entry : sortedMap.entrySet()) {
			Long classificationId = entry.getKey();
			List<GProduct> products = entry.getValue();
			ProductGroupVo productGroupVo = new ProductGroupVo();
			GClassification classification;
			do {
				classification = classificationMap.get(classificationId);
				if (classification == null) {
					classification = classificationService.getById(classificationId);
					if (classification != null) {
						classificationMap.put(classificationId, classification);
					}
				}
				if (classification != null) {
					productGroupVo.getClassificationNameList().add(classification.getName());
					classificationId = classification.getParentId();
				}
			} while (classification != null && classificationId != 0);
			Collections.reverse(productGroupVo.getClassificationNameList());
			// 排序同类别下的商品
			products.sort(Comparator.comparingInt(GProduct::getSort));
			productGroupVo.setProductList(products);
			productGroupVoList.add(productGroupVo);
		}
		return productGroupVoList;
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public Result<?> saveProduct(SaveProductRequest request) {
		GProduct product = GProductConverter.saveRequestToPo(request);
		List<GProductRequirement> requirementList = request.getRequirementList();
		List<GProductUnlock> unlockList = request.getUnlockList();
		// 商品
		if (product.getId() == null) {
			product.insert();
		} else {
			product.updateById();
			// 删除现有的成本项和解锁项
			requirementService.lambdaUpdate().eq(GProductRequirement::getProductId, product.getId()).remove();
			unlockService.lambdaUpdate().eq(GProductUnlock::getProductId, product.getId()).remove();
		}
		// 新增成本项和解锁项
		if (CollUtil.isNotEmpty(requirementList)) {
			requirementList.forEach(requirement -> requirement.setProductId(product.getId()));
			requirementService.saveBatch(requirementList);
		}
		if (CollUtil.isNotEmpty(unlockList)) {
			unlockList.forEach(unlock -> unlock.setProductId(product.getId()));
			unlockService.saveBatch(unlockList);
		}
		return Result.success();
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public Result<?> deleteProduct(Long id) {
		removeById(id);
		requirementService.lambdaUpdate().eq(GProductRequirement::getProductId, id).remove();
		unlockService.lambdaUpdate().eq(GProductUnlock::getProductId, id).remove();
		return Result.success();
	}
}
